package top.huxy.boot.controller.admin;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import top.huxy.boot.BlogApiApplication;
import top.huxy.boot.annotation.Master;
import top.huxy.boot.annotation.Operation;
import top.huxy.boot.annotation.RequestCD;
import top.huxy.boot.annotation.RequestRemake;
import top.huxy.boot.model.dto.DTOSchedule;
import top.huxy.boot.model.entity.Admin;
import top.huxy.boot.service.ScheduleService;
import top.huxy.boot.util.ExceptionUtils;
import top.huxy.boot.util.StringUtils;
import top.huxy.boot.util.obj.Result;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;

/**
 * 任务控制器
 */
@RestController
@Slf4j
@RequestMapping("/admin/schedule")
public class ScheduleController {

    ScheduleService scheduleService;

    public ScheduleController(ScheduleService scheduleService) {
        this.scheduleService = scheduleService;
    }

    @Operation("添加任务")
    @PostMapping("/addSchedule")
    @Master
    public Result addSchedule(DTOSchedule schedule, Admin admin) {

        scheduleService.addSchedule(schedule, admin);

        return Result.success("添加任务成功");
    }

    @Operation("停止任务")
    @GetMapping("/stopSchedule")
    @Master
    public Result stopSchedule(@RequestParam("id") Integer scheduleId, Admin admin) {
        scheduleService.stopSchedule(scheduleId, admin);

        return Result.success("关闭任务成功");
    }

    @Operation("启用任务")
    @GetMapping("/enableSchedule")
    @Master
    public Result enableSchedule(@RequestParam("id") Integer scheduleId, Admin admin) {
        scheduleService.enableSchedule(scheduleId, admin);

        return Result.success("启用任务成功");
    }

    @GetMapping("/getScheduleList")
    @RequestRemake("获取任务列表")
    public Result getScheduleList() {
        return Result.success(scheduleService.getScheduleList());
    }

    @Operation("运行一次任务")
    @GetMapping("/runOnce/{id}")
    @Master
    public Result runOnce(@PathVariable("id") Integer scheduleId) {
        scheduleService.runOnce(scheduleId);
        return Result.success("执行成功");
    }

    @RequestCD(time = 250)
    @GetMapping("/searchBeanName")
    @Master
    @RequestRemake("搜索bean")
    public Result searchBeanName(@RequestParam(name = "beanName", required = false) String beanName) {
        //非空判断
        if (StringUtils.isEmpty(beanName)) return Result.success(Collections.emptyList());

        //去除前后空格
        beanName = beanName.trim();

        //获取容器中所有bean名
        String[] beanDefinitionNames = BlogApiApplication.app.getBeanDefinitionNames();

        //准备结果集
        LinkedList<String> res = new LinkedList<>();

        //遍历所有bean名
        for (String bean : beanDefinitionNames) {
            //如果bean名和beanName匹配，将结果添加到结果集
            if (bean.startsWith(beanName)) {
                res.add(bean);
                //如果结果集数量大于等于10，退出搜索
                if (res.size() > 9) break;
            }
        }

        //返回结果集
        return Result.success(res);
    }

    @RequestCD(time = 250)
    @GetMapping("/searchBeanMethod")
    @Master
    @RequestRemake("搜索bean方法")
    public Result searchBeanMethod(@RequestParam(name = "beanName", required = false) String beanName, @RequestParam(name = "methodName", required = false) String methodName) {
        //非空判断
        if (StringUtils.isEmpty(beanName, methodName)) return Result.success(null);

        //去除前后空格
        beanName = beanName.trim();
        methodName = methodName.trim();

        //根据名称获取bean
        Object bean;
        try {
            bean = BlogApiApplication.app.getBean(beanName);
        } catch (Exception e) {
            //抛异常说明没有该bean，返回null
            return Result.success(null);
        }

        /*
         * 因为bean是代理后的对象，里面有一大堆方法，所以需要获取源对象才行
         * 好在bean的toString方法没被代理对象重写，所以可以根据toString方法获取源对象的类名
         * 这也说明，写定时任务类时，不要重写它的toString，不然这里获取不到原类名
         */
        String rawBean = bean.toString().substring(0, bean.toString().indexOf('@'));

        Class<?> aClass;
        try {
            //获取原类的字节码对象
            aClass = Class.forName(rawBean);
        } catch (ClassNotFoundException e) {
            //一般情况，都是可以获取到原对象字节码对象的
            log.error("不该出现的异常" + e);
            ExceptionUtils.logError(e);
            return Result.clientError("不该发生的错误");
        }


        //获取源对象的所有public方法
        Method[] methods = aClass.getMethods();

        //准备结果集
        HashSet<String> res = new HashSet<>();

        //遍历源对象的所有public方法
        for (Method method : methods) {
            String name = method.getReturnType().getName();
            if ("java.lang.String".equals(name) && !"toString".equals(method.getName())) {
                //如果方法名和methodName匹配，将源对象方法添加到结果集
                if (method.getName().startsWith(methodName)) {
                    res.add(method.getName());

                    //结果集数量大于等于10，不再搜索
                    if (res.size() > 9) break;
                }
            }

        }

        //返回结果集
        return Result.success(res);
    }
}
